using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using WindowsGame1.gamePlugins.renderer;
using WindowsGame1.gamePlugins.powerups;
using WindowsGame1.gamePlugins.nxt;
using WindowsGame1.gamePlugins.menu;
using System.Timers;

namespace WindowsGame1
{

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        public static Game1 game;

        /* graphics spul declareren */
        GraphicsDeviceManager graphics;
        GraphicsDevice device;
        SpriteBatch spriteBatch;
        // custom classes
        GameDisplay gameDisplay;
        ControllerBridgeNXT nxt;
        Physics engine;
        FPS fps;
        Score score;
        ScoreScreen scoreScreen;
        IngameMenu menu;
        SpriteFont spriteFont;
        // Grootte van het scherm
        int displayMode = (int)GameDisplay.display.FULLSCREEN_MODE_1280;
        float middenvanhetscherm;
        bool setBallPosition = false;
        bool powerupsInintialised = false;
        String calibratieText = "Calibratie Modus\np1: < >\np2: Up Down\nTerug: Esc";
        // alle objecten
        Texture2D middenlijn;
        public List<PhysicsObject> objectsx;
        Timer timerClock = new Timer();    
        

        public enum GameState {
            MainMenu, InSPGame, InMPGame,	
            Calibration, Pause, ScoreScreen 
        }
        public GameState gameState = GameState.MainMenu;
        GameState previousState = GameState.InSPGame;

        public Game1()
        {
            game = this;
            graphics = new GraphicsDeviceManager(this);
            this.Window.AllowUserResizing = true;
            graphics.IsFullScreen = true;
        }

        protected override void Initialize()
        {
            gameDisplay = new GameDisplay();
            graphics = gameDisplay.setWindow(graphics, displayMode);
            device = graphics.GraphicsDevice;
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Content.RootDirectory = "Content";
            spriteFont = Content.Load<SpriteFont>("Font");
            engine = new Physics(Content);
            fps = new FPS(Content);
            score = new Score(Content);
            scoreScreen = new ScoreScreen(Content);
            menu = new IngameMenu(Content, spriteBatch);
            nxt = new ControllerBridgeNXT(this);
            nxt.maxHeight = gameDisplay.getViewPort()[0];
            middenvanhetscherm = (gameDisplay.getViewPort()[0] / 2) - 138;
            base.Initialize();  
        }

        protected override void LoadContent()
        {   // lijst van objecten die op de scene worden getekent, 
            // de properties kan je terugvinden in PhysicsObject.cs
            middenlijn = Content.Load<Texture2D>("middenlijn");
            objectsx = new List<PhysicsObject>
            {
               new PhysicsObject {name="pongball", texture=Content.Load<Texture2D>("pongbalwit"), acceleration=new Vector2(1.001F, 1.001F), position=new Vector2(middenvanhetscherm, middenvanhetscherm), speed=randomNumber(), scale=1F},
               new PhysicsObject {name="player1", texture=Content.Load<Texture2D>("plankje"), speed=Vector2.Zero, position=new Vector2(80F, 0), scale=1F},
               new PhysicsObject {name="player2", texture=Content.Load<Texture2D>("plankje"), speed=Vector2.Zero, position=new Vector2(gameDisplay.getViewPort()[0] - 86F, 0), scale=1F}
            };

            // de objecten van de powerups worden aan de lijst toegevoegd
            objectsx = engine.powerups.initialize(objectsx);
        }

        protected override void UnloadContent() {
            nxt.unload();
        }

        protected override void Update(GameTime gameTime)
        {
            // Keyboard quit event
            if (Keyboard.GetState().IsKeyDown(Keys.Q))
                this.Exit();

            // in welke staat verkeert ons programma
            switch(this.gameState)	{
               case GameState.MainMenu:
                    menu.update(gameTime);
                    switch (menu.clicked)
                    {
                        case IngameMenu.optionmenu.singleplayer:
                            // start nieuw singleplayer spel
                            resetGame();
                            gameState = GameState.InSPGame;
                        break;
                        case IngameMenu.optionmenu.multiplayer:
                            // start nieuw multiplayer spel
                            resetGame();
                            menu.clicked = IngameMenu.optionmenu.none;
                            gameState = GameState.InMPGame;
                        break;
                        case IngameMenu.optionmenu.resume:
                            // TODO: verander dit
                            gameState = previousState;
                        break;
                        case IngameMenu.optionmenu.calibrate:
                            calibratieText = "Calibratie Modus\np1: < >\np2: Up Down\nTerug: Esc";
                            gameState = GameState.Calibration;
                        break;
                        case IngameMenu.optionmenu.quit:
                            // einde van het spel
                            this.Exit();
                        break;
                        default:
                        break;
                    }
                    menu.clicked = IngameMenu.optionmenu.none;
                    break;
                case GameState.InMPGame:
                case GameState.InSPGame:
                    if (Keyboard.GetState().IsKeyDown(Keys.Escape) || Mouse.GetState().RightButton == ButtonState.Pressed)
                    {
                        previousState = gameState;
                        gameState = GameState.MainMenu;
                    }
                    // Dit linkt naar de nxt
                    nxt.update(gameTime, engine.powerups.pu, score);
                    objectsx[1].position.Y = nxt.betje1;

                    //if (gameState == GameState.InMPGame || true)
                    //{
                        objectsx[2].position.Y = nxt.betje2;
                   // }
                    //else
                    //{
                        // COMPUTER BESTURING IN SINGLEPLAYER
                        //objectsx[2].position.Y = nxt.multiplayerCPU((int)objectsx[0].position.X, (int)objectsx[0].position.Y, (int) objectsx[2].position.Y);
                    //}
                    if (score.player1score > 9 || score.player2score > 9)
                    {
                        gameState = GameState.ScoreScreen;
                    }
                    // alle objecten worden een frame later gerendert, botsingen etc werken hierdoor
                    objectsx = engine.renderframe(objectsx, gameTime, gameDisplay.getViewPort(), nxt, this);
                    fps.update(gameTime);
                    score.update(gameTime, engine.getScore());
                    break;
                case GameState.Calibration:
                    nxt.update(gameTime, engine.powerups.pu, score);
                    engine.renderframe(objectsx, gameTime, gameDisplay.getViewPort(), nxt, this);

                    if (Keyboard.GetState().IsKeyDown(Keys.Left))
                    {
                        // p1 links gecalibreert
                        nxt.calibrate(ControllerBridgeNXT.Calibrate_value.p1_left);
                        calibratieText += "\nP1 Links gecalibreerd";
                    }
                    else if (Keyboard.GetState().IsKeyDown(Keys.Right))
                    {
                        // p1 rechts gecalibreert
                        nxt.calibrate(ControllerBridgeNXT.Calibrate_value.p1_right);
                        calibratieText += "\nP1 Rechts gecalibreerd";
                    }
                    else if (Keyboard.GetState().IsKeyDown(Keys.Up))
                    {
                        // p2 links gecalibreert
                        nxt.calibrate(ControllerBridgeNXT.Calibrate_value.p2_left);
                        calibratieText += "\nP2 Links gecalibreerd";
                    }
                    else if (Keyboard.GetState().IsKeyDown(Keys.Down))
                    {
                        // p2 rechts gecalibreert
                        nxt.calibrate(ControllerBridgeNXT.Calibrate_value.p2_right);
                        calibratieText += "\nP2 Rechts gecalibreerd";
                    }
                    else if (Keyboard.GetState().IsKeyDown(Keys.Escape) || Mouse.GetState().RightButton == ButtonState.Pressed)
                    {
                        // stop calibreren
                        calibratieText += "\nCalibratieModus EXIT";
                        gameState = GameState.MainMenu;
                    }
                break;
                case GameState.ScoreScreen:
                    scoreScreen.update(gameTime, new int[]{score.player1score, score.player2score});
                    if (Keyboard.GetState().IsKeyDown(Keys.Escape) || Mouse.GetState().RightButton == ButtonState.Pressed)
                    {
                        resetGame();
                        gameState = GameState.MainMenu;
                    }
                break;
            }

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            Color achtergrondKleur = new Color(engine.powerups.rood, engine.powerups.groen, engine.powerups.blauw);
            GraphicsDevice.Clear(achtergrondKleur);
            
            // in welke staat verkeert ons programma
            switch (gameState)
            {
                case GameState.MainMenu:
                    IsMouseVisible = true;
                    resetBgColor();
                    // laad het mainmenu scherm zien
                    menu.draw();
                    break;
                case GameState.InMPGame:
                case GameState.InSPGame:

                    // laat het spel zien
                    IsMouseVisible = false; 
                    spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);

                    // middenlijn tekenen
                    float middenvanhetscherm2 = (gameDisplay.getViewPort()[0] / 2) - (middenlijn.Width/2);
                    for (int j = 0; j <= gameDisplay.getViewPort()[1]; j=j+100 )
                    {
                        Vector2 lijn = new Vector2(middenvanhetscherm2, j);
                        spriteBatch.Draw(middenlijn, lijn, null, Color.White);
                    }

                    // Teken alle objecten
                    for (int i = objectsx.Count - 1; i >= 0; i--)
                    {
                        PhysicsObject obj = objectsx[i];
                        if (obj != null && obj.texture != null && obj.visible == true)
                        {
                            spriteBatch.Draw(obj.texture, obj.position, null, Color.White, obj.rotation, obj.origin, obj.scale, obj.effects, obj.layerDepth);
                        }
                    }

                    // teken fps en score
                    fps.draw(spriteBatch);
                    score.draw(spriteBatch, new Vector2(middenvanhetscherm, 50F));

                    spriteBatch.End();
                    break;
                case GameState.Pause:
                    // onderbreek het spel en laat een pause tekst erboven
                    break;
                case GameState.ScoreScreen:
                    spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
                    // middenlijn tekenen
                    float middenvanhetscherm3 = (gameDisplay.getViewPort()[0] / 2) - (middenlijn.Width / 2);
                    for (int j = 0; j <= gameDisplay.getViewPort()[1]; j = j + 100)
                    {
                        Vector2 lijn = new Vector2(middenvanhetscherm3, j);
                        spriteBatch.Draw(middenlijn, lijn, null, Color.White);
                    }
                    spriteBatch = scoreScreen.draw(spriteBatch, new Vector2(middenvanhetscherm, 50F));
                    spriteBatch.End();
                    break;
                case GameState.Calibration:
                    spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
                    spriteBatch.DrawString(spriteFont, calibratieText, Vector2.One, Color.White);
                    spriteBatch.End();
                    break;

            }
           
            base.Draw(gameTime);
        }

        // reset de bal en zorg dat powerups stoppen
        public void resetBall()
        {
            // controleer de score, wint er iemand?
            if (score.player1score > 9 || score.player2score > 9)
            {
                // Score weergeven en de winnaar bekend maken
                gameState = GameState.ScoreScreen;
            }
            resetPowerUps();
            objectsx[0].position = new Vector2(middenvanhetscherm + 108, middenvanhetscherm - 100);
            // zorg dat speed 3 seconden 0 blijft, en dan veranderd in dit
            objectsx[0].speed = new Vector2(0, 0);
            //engine.powerups.aangeroepen = true;
            resetBgColor();
            timerClock.Elapsed += new ElapsedEventHandler(OnTimer);
            timerClock.Interval = 3000;
            timerClock.Enabled = true;
        }

        public void resetPowerUps()
        {
            engine.powerups.shouldWait = true;
            engine.powerups.pu = new bool[7];
            engine.powerups.timeraan = false;
            engine.powerups.aangeroepen = false;
            engine.powerups.timeraan2 = false;
            engine.powerups.interval = 0;
            engine.powerups.interval2 = 0;
            engine.powerups.miliseconds = 0;
            objectsx[0].scale = 1F;
            for (int i = 4; i < 7; i++)
            {
                objectsx[i].visible = false;
                objectsx[i].solidCollision = false;
            }
        }

        public void OnTimer(Object source, ElapsedEventArgs e)
        {
            objectsx[0].speed = randomNumber();
            timerClock.Enabled = false;
            engine.powerups.shouldWait = false;
            //engine.powerups.aangeroepen = false;
            //engine.powerups.timeraan = true;
            //engine.powerups.timeraan2 = true;
        }

        // reset het spel
        public void resetGame()
        {
            resetBall();
            score.player1score = 0;
            score.player2score = 0;

            engine.scorePlayer1 = 0;
            engine.scorePlayer2 = 0;
            //engine.powerups.timeraan = false;
            //engine.powerups.aangeroepen = false;
            //engine.powerups.interval = 0;
            //engine.powerups.miliseconds = 0;
            //LoadContent();
        }

        public void resetBgColor()
        {
            /*for (int i = 4; i <= 7; i++)
            {
                objectsx[i].visible = false;
            }*/
            engine.powerups.rood = 0;
            engine.powerups.groen = 0;
            engine.powerups.blauw = 0;
        }

        public Vector2 randomNumber()
        {
            float speed = 3F;
            float rotation = 0F;
            float velocityX = 0, velocityY = 0;
            
            Random r = new Random();
            while (velocityX < 1 && velocityX > -1 || velocityY < 1 && velocityY > -1)
            {
                rotation = r.Next(360);
                velocityX = (float)Math.Sin(rotation * Math.PI / 180d) * speed;
                velocityY = (float)Math.Cos(rotation * Math.PI / 180d) * -speed;
            }
            return new Vector2(velocityX, velocityY);
        }

    }

}